<?php
namespace app\api\services;

use app\api\cache\KeysUtil;
use app\api\cache\RedisCache;
use app\api\consDir\CommunityConst;
use app\api\consDir\ErrorConst;
use app\common\libs\Singleton;
use app\common\models\Carefree\CarefreeOrder;
use app\common\models\Community\CommunityOpOrder;
use app\common\models\Community\CommunityOrder;
use app\common\models\Community\CommunityUser;
use app\common\models\Community\PrepayCommunityOrder;
use app\common\models\Order\Order;
use app\common\models\Order\OrderGoods;
use app\common\models\Order\OrderPay;
use app\common\utils\CommonUtil;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\facade\Log;

class PayService
{
    use Singleton;

    /**
     * 支付完成
     * @param $data
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function payFormOrder($data): bool
    {
        //分布式锁 处理生产者发送多条相同消息
        $lock = RedisCache::set('order:lock:'.$data['pay_no'], 1, ['NX', 'EX' => 3]);
        if(!$lock){
            return false;
        }
        //获取支付订单信息
        $payInfo = $this->payInfo($data['pay_no'], $data['pay_status']);
        if (empty($payInfo)) {
            return false;
        }
        OrderPay::getInstance()->startTrans();
        try {
            $payData = [
                'trade_no' => $data['trade_no'],
                'status'   => 1,
            ];
            $pay = OrderPay::getInstance()->where(['pay_no' => $payInfo['payNo']])->update($payData);
            if ( ! $pay) {
                OrderPay::getInstance()->rollback();
                return false;
            }

            $orderSn = substr($payInfo['orderNo'], 0, 2);
            switch ($orderSn) { //服务商订单
                case 'ST':
                    $order = ServiceTeamService::getInstance()->payCallback($payInfo['orderNo'], $data['trade_no']);
                    if ( ! $order) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    $userPartner = MemberService::getInstance()->addUserPartner($payInfo['userId'], 1);
                    if ( ! $userPartner) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    if ($payInfo['payAmount'] > 0) {
                        $msg = '服务商购买,支付金额:' . $payInfo['payAmount'];
                        MemberService::getInstance()->addFinanceLog($payInfo['userId'], 'service_pay', $payInfo['payAmount'], 3, $msg, $orderSn);
                    }
                    break;
                case 'NO': //线下订单
                case 'OL': //线上订单
                case 'SU': //供应链订单
                    $order = OrderService::getInstance()->payCallback($payInfo['orderNo'], $data['trade_no'],$payInfo['payNo']);
                    if ( ! $order) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    if ($payInfo['payPrice'] > 0 && $payInfo['payStatus'] == 3) {
                        $msgType   = ['NO' => '线下消费抵扣', 'OL' => '线上消费抵扣', 'SU' => '供应链消费抵扣'];
                        $msg       = $msgType[$orderSn] . '，抵扣订单' . $payInfo['orderNo'];
                        $orderType = ['NO' => 'pay_offline', 'OL' => 'pay_online', 'SU' => 'pay_supply'];
                        MemberService::getInstance()->addFinanceLog($payInfo['userId'], $orderType[$orderSn], $payInfo['payPrice'], 1, $msg);
                    }

                    if ($orderSn == 'NO') { // 线下单检查会员等级升级
                        try {
                            \app\api\services\UserLevelService::getInstance()->checkUpgrade(
                                $payInfo['userId']
                            );
                        } catch (\Exception $e) {
                            \think\facade\Log::error($e->getMessage());
                        }
                    }

                    try {
                        // 支付回调，坚持邀请人、邀请人的邀请人是否可以升级
                        $invite    = \think\facade\Db::table('member')->where('id', $payInfo['userId'])->field('invite_id,invite_third_id')->find();
                        $inviteId  = $invite['invite_id'] ?? 0;
                        $inviteId2 = $invite['invite_third_id'] ?? 0;
                        if ($inviteId > 0) {
                            \app\api\services\UserLevelService::getInstance()->checkUpgrade(
                                $inviteId
                            );
                        }
                        if ($inviteId2 > 0) {
                            \app\api\services\UserLevelService::getInstance()->checkUpgrade(
                                $inviteId2
                            );
                        }
                    } catch (\Exception $e) {
                        \think\facade\Log::error($e->getMessage());
                    }
                    try {
                        //活跃值
                        MemberService::getInstance()->setActive($payInfo['userId'], 2, 1, 0);
                        //激活后活跃值恢复
                        $memberOrder = Order::getInstance()->where(['order_no' => $payInfo['orderNo']])->find();
                        if ($memberOrder['specialId'] > 0) {
                            MemberService::getInstance()->recoverActivity($payInfo['userId'], $memberOrder['specialId']);
                        } elseif ($memberOrder['orderType'] == 2) {
                            $goodsIdArr = OrderGoods::getInstance()->where('order_no', $payInfo['orderNo'])->column('goods_id');
                            MemberService::getInstance()->recoverActivity($payInfo['userId'], 0, $goodsIdArr);
                        }
                    } catch (\Exception $e) {
                        \think\facade\Log::error($e->getMessage());
                    }

                    //赠送抽奖次数
                    LotteryService::getInstance()->send($payInfo['userId'],2,$payInfo['payPrice'],$payInfo['orderNo']);
                    LotteryService::getInstance()->inviteUserConsume($payInfo['userId'], 1, $payInfo['payPrice'], $payInfo['orderNo']);
                    break;
                case 'SO': //签到订单
                    $communitySign = CommunityService::getInstance()->callbackSign($payInfo['orderNo']);
                    if ( ! $communitySign) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    if ($payInfo['communityPayAmount'] > 0) {
                        $msg = '社区购买,支付金额:' . $payInfo['communityPayAmount'];
                        MemberService::getInstance()->addFinanceLog($payInfo['userId'], 'sign_pay', $payInfo['communityPayAmount'], 3, $msg, $payInfo['orderNo']);
                    }
                    break;
                case 'CO': //社区订单
                    $communityOrder = CommunityService::getInstance()->getOrder($payInfo['orderNo']);
                    if (empty($communityOrder) || $communityOrder['status'] != 1) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }

                    $communityUser = CommunityService::getInstance()->getCommunityUser($communityOrder['communityId']);
                    if (empty($communityUser)) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }

                    $order = CommunityService::getInstance()->payCallback($payInfo, $data, $communityOrder, $communityUser);
                    if ( ! $order) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }

                    if ($payInfo['communityPayAmount'] > 0) {
                        $msg = '竞拍社区抵扣:' . $payInfo['communityPayAmount'];
                        MemberService::getInstance()->addFinanceLog($payInfo['userId'], 'pay_community', $payInfo['communityPayAmount'], 1, $msg, $payInfo['orderNo']);
                    }

                    //修改红包 sign_status 2入驻已使用
                    if ($payInfo['signPrice'] > 0) {
                        $bag = CommunityService::getInstance()->setUserBag($payInfo['userId'], 2);
                        if ( ! $bag) {
                            OrderPay::getInstance()->rollback();
                            return false;
                        }
                    }

                    //更新预付尾款
                    $this->updatePrepayFinal($communityOrder);
                    //赠送抽奖次数
                    $money = $payInfo['payPrice'] > 0 ? $payInfo['payPrice'] : $payInfo['communityPayAmount'];
                    LotteryService::getInstance()->send($payInfo['userId'],2,$money,$payInfo['orderNo']);
                    LotteryService::getInstance()->inviteUserConsume($payInfo['userId'], 1, $money, $payInfo['orderNo']);
                    $ret = $this->afterAction($payInfo);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    break;
                case 'OP': //转让订单
                    $where = [
                        ['order_no', '=', $payInfo['orderNo']],
                    ];

                    $opOrder = CommunityOpOrder::getInstance()->where($where)->find();
                    //已支付
                    if ( ! $opOrder || $opOrder['isPay'] == 1) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }

                    $data = [
                        'is_pay' => 1,
                        'pay_at' => date('Y-m-d H:i:s'),
                    ];
                    $order = CommunityOpOrder::getInstance()->where($where)->update($data);
                    if ( ! $order) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    //更新社区
                    $data = [
                        'community_status' => CommunityConst::CHECK_STATUS,
                        'is_pay_service'   => CommunityConst::PAY_SERVICE,
                        'op_time'          => date('Y-m-d H:i:s'),
                    ];
                    $communityUser = CommunityUser::getInstance()->where('op_order_no', $payInfo['orderNo'])->update($data);
                    if ( ! $communityUser) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }

                    if ($payInfo['communityPayAmount'] > 0) {
                        $msg = '支付服务费,支付金额:' . $payInfo['communityPayAmount'];
                        MemberService::getInstance()->addFinanceLog($opOrder['payUserId'], 'pay_service', $payInfo['communityPayAmount'], 1, $msg, $orderSn);
                    }

                    //增加转让次数
                    CommunityService::getInstance()->addTransferCount($payInfo['userId'],$payInfo['orderNo']);

                    //支付服务费后分红
                    $ret = CommunityService::getInstance()->dividend($opOrder, $payInfo['orderNo']);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    //发放优惠券
                    CouponService::getInstance()->sendCoupon($payInfo['userId']);

                    //发放事业部分红
                    $rabbitmqData = ['type' => 'community_business','order_no' => $payInfo['orderNo']];
                    RabbitMqService::sendDelay($rabbitmqData, 3);
                    break;
                case 'PA': //礼包订单
                    $ret = PacksService::getInstance()->payCallback($payInfo['orderNo']);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    //赠送抽奖次数
                    $money = $payInfo['payAmount'] > 0 ? $payInfo['payAmount'] :$payInfo['payPrice'];
                    LotteryService::getInstance()->send($payInfo['userId'],2,$money,$payInfo['orderNo']);
                    LotteryService::getInstance()->inviteUserConsume($payInfo['userId'], 1, $money, $payInfo['orderNo']);
                    break;
                case 'RC': //充值
                    $ret = RechargeService::getInstance()->payCallback($payInfo['orderNo']);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    break;
                case 'HA': //招募大厅
                    $communityOrder = CommunityService::getInstance()->getOrder($payInfo['orderNo']);
                    if (empty($communityOrder) || $communityOrder['status'] != 1) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    if ($payInfo['communityPayAmount'] > 0) {
                        $msg = '招募社区抵扣:' . $payInfo['communityPayAmount'];
                        MemberService::getInstance()->addFinanceLog($payInfo['userId'], 'pay_community', $payInfo['communityPayAmount'], 1, $msg, $payInfo['orderNo']);
                    }

                    $communityUser = CommunityService::getInstance()->getCommunityUser($communityOrder['communityId']);
                    if (empty($communityUser)) {
                        $ret = CommunityService::getInstance()->createCommunityUser($communityOrder['communityId'], $payInfo['userId'], $communityOrder['price']);
                        if(!$ret){
                            OrderPay::getInstance()->rollback();
                            return false;
                        }
                        $communityUser = CommunityService::getInstance()->getCommunityUser($communityOrder['communityId']);
                    }else{
                        if($communityUser['communityStatus'] == 8){
                            OrderPay::getInstance()->rollback();
                            return false;
                        }
                    }

                    $order = CommunityService::getInstance()->HaPayCallback($payInfo, $data, $communityOrder, $communityUser);
                    if ( ! $order) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    //分红
                    $ret = CommunityService::getInstance()->dividendHall($communityUser,$payInfo['orderNo']);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    //升级服务商
                    PacksService::getInstance()->upgradeService($payInfo['userId']);
                    //赠送抽奖次数
                    $money = $payInfo['communityPayAmount'] > 0 ? $payInfo['communityPayAmount'] :$payInfo['payPrice'];
                    LotteryService::getInstance()->send($payInfo['userId'],2,$money,$payInfo['orderNo']);
                    LotteryService::getInstance()->inviteUserConsume($payInfo['userId'], 1, $money, $payInfo['orderNo']);
                    $ret = $this->afterActionHall($payInfo);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    break;
                case 'OC': //购买转让大厅中社区
                    //赠送抽奖次数
                    LotteryService::getInstance()->send($payInfo['userId'],2,$payInfo['payPrice'],$payInfo['orderNo']);
                    LotteryService::getInstance()->inviteUserConsume($payInfo['userId'], 1, $payInfo['payPrice'], $payInfo['orderNo']);
                    $ret = CommunityService::getInstance()->OcPayCallback($payInfo);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    break;
                case 'PR': //预约社区订单
                    $ret = CommunityService::getInstance()->PrPayCallback($payInfo);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    break;
                case 'WY': //无忧
                    if ($payInfo['payPrice'] > 0 && $payInfo['payStatus'] == 3) {
                        $msg = '无忧订单抵扣' . $payInfo['payPrice'];
                        MemberService::getInstance()->addFinanceLog($payInfo['userId'], 'pay_carefree', $payInfo['payPrice'], 1, $msg, $payInfo['orderNo']);
                    }
                    $ret = CarefreeInfoService::getInstance()->payCallback($payInfo);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    break;
                case 'CD': //会员卡
                    $ret = CardService::getInstance()->payCallback($payInfo);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    break;
                case 'SE': //生活馆
                    $ret = ServiceCenterService::getInstance()->payCallback($payInfo);
                    if ( ! $ret) {
                        OrderPay::getInstance()->rollback();
                        return false;
                    }
                    break;
            }

        } catch (\Exception $e) {
            Log::error($e->getMessage().$e->getLine().$e->getFile());
            OrderPay::getInstance()->rollback();
            return false;
        }
        OrderPay::getInstance()->commit();

        //缓存支付订单号
        RedisCache::setEx(KeysUtil::getOrderCallbackKey($payInfo['orderNo']), 60, $payInfo['userId']);
        return true;
    }

    /**
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     * @throws Exception
     */
    public function afterAction($payInfo): bool
    {
        //赠送贡献值
        //$msg = '社区竞拍，赠送贡献值，订单' . $payInfo['orderNo'];
        //$amount = $payInfo['communityPayAmount'] > 0 ? $payInfo['communityPayAmount'] : $payInfo['payPrice'];
        //MemberService::getInstance()->addFinanceLog($payInfo['userId'], 'community', $amount, 7, $msg, $payInfo['orderNo']);
        //赠送第一次竞拍
        $where = [
            ['status', '=', 2],
            ['user_id', '=', $payInfo['userId']],
        ];
        $count = CommunityOrder::getInstance()->where($where)->count();
        if ($count <= 1) {
            MemberService::getInstance()->sendNewTaskGxz($payInfo['userId'], 'first_community', '第一次竞拍社区');
        }
        CommunityService::getInstance()->getCommunityInviteMoney($payInfo);
        return true;
    }

    public function updatePrepayFinal($order): bool
    {
        if($order['prepayPrice'] <= 0){
            return false;
        }
        $where = [
            ['is_final','=',0],
            ['is_refund','=',0],
            ['community_id','=',$order['communityId']],
            ['user_id','=',$order['userId']],
        ];
        $data = [
            'is_final' => 1,
            'community_order_no' => $order['orderNo'],
            'update_at' => date('Y-m-d H:i:s')
        ];
        PrepayCommunityOrder::getInstance()->where($where)->update($data);
        return true;
    }

    /**
     * 招募大厅
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws Exception
     */
    public function afterActionHall($payInfo): bool
    {
        CommunityService::getInstance()->getCommunityInviteMoneyHall($payInfo);
        $where = [
            ['status', '=', 2],
            ['user_id', '=', $payInfo['userId']],
        ];
        $count = CommunityOrder::getInstance()->where($where)->count();
        if ($count <= 1) {
            MemberService::getInstance()->sendNewTaskGxz($payInfo['userId'], 'first_community', '第一次竞拍社区');
        }
        return true;
    }

    /**
     * @param $payNo
     * @param int $type
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function payInfo($payNo, int $type = 1): array
    {
        $where = [
            ['pay_no', '=', $payNo],
            ['status', '=', 0],
            ['pay_status', '=', $type],
        ];
        $orderPay = OrderPay::getInstance()->where($where)->find();
        return empty($orderPay) ? [] : $orderPay->toArray();
    }

    public function toPay($payInfo, $userInfo, $type, $paySubType = '')
    {
        $data = [];
        switch ($type) {
            case 1: //微信
                $data = WechatPayService::getInstance()->index($payInfo, $userInfo);
                break;
            case 2: //支付宝
                $data = AlipayService::getInstance()->appPay($payInfo, $paySubType);
                break;
        }
        return $data;
    }

    /**
     * @param $uid
     * @param $order
     * @param $payType
     * @return array
     * @throws DbException
     */
    public function payOrder($uid, $order, $payType): array
    {
        // 0待支付 1已支付 2已取消
        $orderPay = \think\facade\Db::table('order_pay')
            ->where('order_no', $order['orderNo'])
            ->find();
        $status    = $orderPay['status'] ?? -1;
        $create_at = $orderPay['create_at'] ?? '';
        if ($status == 1) {
            CommonUtil::throwException(
                ErrorConst::ORDER_STATUS_ERROR,
                ErrorConst::ORDER_STATUS_ERROR_MSG
            );
        }
        $create_at = empty($create_at) ? 0 : strtotime($create_at);
        $diff      = time() - $create_at;

        $orderSn = substr($order['orderNo'], 0, 2);
        $typeArr = [
            'OL' => 0, //线上
            'SU' => 5, //供应链单
            'NO' => 6, //线下
            'HA' => 7, //话费
            'WY' => 10, //无忧
            'CD' => 11, //会员卡
            'SE' => 12, //服务
        ];
        if ($status == 0 && $diff < 5) {
            $data = [
                'user_id'      => $orderPay['user_id'],
                'pay_amount'   => $orderPay['pay_amount'],
                'pay_price'    => $orderPay['pay_price'],
                'order_no'     => $orderPay['order_no'],
                'pay_no'       => $orderPay['pay_no'],
                'pay_status'   => $orderPay['pay_status'],
                'order_status' => $orderPay['order_status'],
                'expire_at'    => $orderPay['expire_at'],
            ];
        } else {
            $data = [
                'user_id'      => $uid,
                'pay_amount'   => $order['payAmount'] ?? 0,
                'pay_price'    => $order['payPrice'] ?? $order['pay_price'],
                'order_no'     => $order['orderNo'] ?? $order['order_no'],
                'pay_no'       => getNo($orderSn . 'PAY'),
                'pay_status'   => $payType,
                'order_status' => $typeArr[$orderSn],
                'expire_at'    => date('Y-m-d H:i:s', strtotime('+15 minute')),
            ];
            if ($orderSn == 'NO') {
                $count = OrderGoods::getInstance()->where('order_no', $order['orderNo'])->count();
                //店铺订单类型 1线上订单 2线下扫码支付 3线下套餐支付
                $data['shop_status'] = 2;
                if ($count > 0) {
                    //优惠套餐
                    $data['shop_status'] = 3;
                }
            }
            if ($orderSn == 'OL') {
                $data['shop_status'] = 1;
            }
            $data['community_order_id'] = RedisCache::get(KeysUtil::getCommunityTaskKey($uid)) ?: 0;
            OrderPay::getInstance()->insert($data);
        }
        return $data;
    }

}
